package com.xbongbong.paas.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.formula.service.FunctionService;
import com.xbongbong.paas.constant.ConditionConstant;
import com.xbongbong.paas.constant.MessageConstant;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.ext.CommitVerifyConditionEntityExt;
import com.xbongbong.paas.domain.entity.ext.PaasProcessTemplateNodeEntityExt;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.TaskTypeEnum;
import com.xbongbong.paas.enums.clazz.ConditionClass;
import com.xbongbong.paas.help.ConditionListHelp;
import com.xbongbong.paas.model.PaasProcessTemplateNodeModel;
import com.xbongbong.paas.pojo.dto.ConditionGetDTO;
import com.xbongbong.paas.pojo.dto.ConditionListDTO;
import com.xbongbong.paas.pojo.dto.NodeValidConditionDTO;
import com.xbongbong.paas.pojo.dto.RelationClueConditionListDTO;
import com.xbongbong.paas.pojo.vo.ConditionGetVO;
import com.xbongbong.paas.pojo.vo.ConditionListVO;
import com.xbongbong.paas.pojo.vo.NodeValidConditionVO;
import com.xbongbong.paas.service.ConditionService;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.PaasStringUtil;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.saas.enums.business.MarketActivityThroughEnum;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author: wufeng
 * @date: 2018/9/5 20:37
 * @desrcption:
 */
@Service("conditionService")
public class ConditionServiceImpl implements ConditionService {

    private static final Logger LOG = LoggerFactory.getLogger(ConditionServiceImpl.class);


    @Resource
    private FunctionService functionService;
    @Resource
    private PaasProcessTemplateNodeModel processTemplateNodeModel;

    @Override
    public ConditionGetVO get(ConditionGetDTO conditionGetDTO) throws XbbException {
        ConditionGetVO conditionGetVO = new ConditionGetVO();
        Integer fieldType = conditionGetDTO.getFieldType();
        try {
            FieldTypeEnum fieldTypeEnum = FieldTypeEnum.getFieldTypeEnum(fieldType);
            List<ConditionClass> conditionList = ConditionListHelp.getConditionList(fieldTypeEnum,0);
            conditionGetVO.setConditionList(conditionList);
        }  catch (Exception e) {
            LOG.error("condition数据库根据类型获取筛选条件列表出错", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());

        }
        return conditionGetVO;
    }


    @Override
    public ConditionListVO list(ConditionListDTO conditionListDTO) throws XbbException {
        ConditionListVO conditionListVO = new ConditionListVO();
        try {
            Class clazz = ConditionConstant.class;
            Field[] fields = clazz.getDeclaredFields();
            Map<String, List<ConditionClass>> conditionMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            if(fields != null && fields.length > 0){
                for (Field field: fields) {
                    FieldTypeEnum fieldTypeEnum = FieldTypeEnum.getFieldTypeEnumByAliasLowerCase(field.getName().toLowerCase());
                    if (fieldTypeEnum == null || field.isSynthetic()) {
                        continue;
                    }
                    List<ConditionClass> conditions = ConditionListHelp.getConditionList(fieldTypeEnum,conditionListDTO.getForChart());
                    conditionMap.put(fieldTypeEnum.getType().toString(), conditions);
                }
            }
            conditionListVO.setConditionList(conditionMap);
        } catch (XbbException e) {
            LOG.error("condition数据库获取筛选条件列表出错", e);
            throw e;
        } catch (Exception e) {
            LOG.error("condition数据库获取筛选条件列表出错", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return conditionListVO;
    }

    @Override
    public ConditionListVO relationClueList(RelationClueConditionListDTO conditionListDTO) throws XbbException {
        ConditionListVO conditionListVO = list(conditionListDTO);
        //穿透code的如果是 2， 表示是“有效线索”的穿透，需要把 下拉框的“不等于”放在第一位，这样前端默认展示的就是"不等于"（配合"不等于" "无效状态" 来展示“有效状态 ”）
        if(Objects.nonNull(conditionListVO) &&  Objects.nonNull(conditionListDTO.getThroughCode()) && conditionListDTO.getThroughCode().equals(MarketActivityThroughEnum.EFFECTIVE_CLUE.getCode())){
            Map<String, List<ConditionClass>> conditionList = conditionListVO.getConditionList();
            if(conditionList != null && conditionList.size()>1){
                for(String key : conditionList.keySet()){
                    if(FieldTypeEnum.COMBO.getType().toString().equals(key)){
                        List<ConditionClass> conditionClassList = conditionList.get(key);
                        if(CollectionUtils.isNotEmpty(conditionClassList)){
                            //从集合的第二位开始（因为 noequal 位置如果在第一位 就不需要处理）
                            for(int i = 1 ; i<conditionClassList.size();i++){
                                if("noequal".equals(conditionClassList.get(i).getSymbol())){
                                    //交换位置:把不等于放在第一位 （swap(list,i,j) i是元素原来的位置 ，j是交换之后的位置）
                                    Collections.swap(conditionClassList,i,0);
                                }
                            }
                        }
                    }
                }
            }
        }
        return conditionListVO;
    }

    @Override
    public NodeValidConditionVO nodeValidCondition(NodeValidConditionDTO nodeValidConditionDTO) throws XbbException {
        NodeValidConditionVO nodeValidConditionVO = new NodeValidConditionVO();
        try {
            Integer taskType = nodeValidConditionDTO.getTaskType();
            TaskTypeEnum taskTypeEnum = TaskTypeEnum.getTaskTypeEnum(taskType);

            switch (taskTypeEnum) {
                case COMMIT:
                    // 提交操作
                    nodeValidConditionVO = validValueByCondition(nodeValidConditionDTO);
                    break;
                case COMMIT_PRINT:
                    nodeValidConditionVO = validValueByCondition(nodeValidConditionDTO);
                    break;
                default:
                    nodeValidConditionVO.setResult(true);
                    break;
            }
        } catch (XbbException e) {
          throw e;
        } catch (Exception e) {
            LOG.error("condition数据库节点提交校验条件出错", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }

        return nodeValidConditionVO;
    }

    /**
     * 节点校验流转条件
     * @param nodeValidConditionDTO
     * @return
     * @throws XbbException
     */
    public NodeValidConditionVO validValueByCondition(NodeValidConditionDTO nodeValidConditionDTO) throws XbbException {
        NodeValidConditionVO nodeValidConditionVO = new NodeValidConditionVO();
        try {
            String corpid = nodeValidConditionDTO.getCorpid();

            Long templateNodeId = nodeValidConditionDTO.getTemplateNodeId();
            PaasProcessTemplateNodeEntityExt processTemplateNode = processTemplateNodeModel.getByKey(templateNodeId.intValue(), corpid);
            if(processTemplateNode == null){
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.PROCESS_NODE_NOT_EXIST);
            }
            JSONObject jsonObject = nodeValidConditionDTO.getData();
            List<CommitVerifyConditionEntityExt> conditionList = processTemplateNode.getCommitVerifyConditionList();
            if(conditionList == null) {
                nodeValidConditionVO.setResult(true);
            }else {
                for (CommitVerifyConditionEntityExt verifyCondition: conditionList) {
                    String condition = verifyCondition.getCondition();
                    Object result = conditionValidate(jsonObject, condition);
                    if(result instanceof Boolean){
                        nodeValidConditionVO.setResult(true);
                    }else{
                        nodeValidConditionVO.setResult(false);
                        nodeValidConditionVO.setMsg(verifyCondition.getConditionDesc());
                    }
                }
            }
        }  catch (XbbException e) {
            throw e;
        }  catch (Exception e) {
            LOG.error("condition数据库节点提交校验数据出错", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return nodeValidConditionVO;
    }

    @Override
    public Object conditionValidate(JSONObject jsonObject, String condition) throws XbbException{
        Object result;
        try {
            Iterator<String> iterator = jsonObject.keySet().iterator();
            while (iterator.hasNext()) {
                String key = iterator.next();
                if(condition.indexOf(key) > -1) {
                    Object object = jsonObject.get(key);
                    if(object instanceof JSONArray){
                        // 校验数据校验子表单数据
                        JSONArray jsonArray = jsonObject.getJSONArray(key);
                        for (Object subObject: jsonArray) {
                            JSONObject subJsonObject = (JSONObject) subObject;
                            Iterator<String> subIterator = subJsonObject.keySet().iterator();
                            while (subIterator.hasNext()){
                                String subKey = subIterator.next();
                                if(condition.indexOf(key) > -1) {
                                    condition = PaasStringUtil.replaceString(condition, "${"+key+"."+key+"}", jsonObject.getString(key));
                                }
                            }
                        }
                    }else{
                        condition = PaasStringUtil.replaceString(condition, "${"+key+"}", jsonObject.getString(key));
                    }
                }
            }
            result = functionService.expressRunValue(condition);
        }catch (Exception e) {
            LOG.error("condition公式校验数据出错", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return result;
    }
}
